#ifndef _NT_GAMES_H_
#define _NT_GAMES_H_

#define CREATE_TEAM

#define ntTouchesMoved			ccTouchesMoved
#define ntTouchesBegan			ccTouchesBegan
#define ntTouchesEnded			ccTouchesEnded

#define ntTouchesBegan(x,y)						ccTouchesBegan(x, y)
#define __TouchesBegan(x,y)						ccTouchesBegan(x, y)
#define ntTouchesMoved(x,y)						ccTouchesMoved(x, y)
#define __TouchesMoved(x,y)						ccTouchesMoved(x, y)
#define ntTouchesEnded(x,y)						ccTouchesEnded(x, y)
#define __TouchesEnded(x,y)						ccTouchesEnded(x, y)

#define ntTouchesCancelled ccTouchesCancelled
#define ntSetTouchEnabled(_target_, _value_) (_target_)->setTouchEnabled(_value_)


#include <string>
#include <vector>
#include <map>
#include <stdlib.h>     /* srand, rand */
#include <stack>
#include <time.h>       /* time */
#include "cocos2d.h"
#include "cocos-ext.h"
#include "CCEGLView.h"
#include "CCScrollView.h"
#include "CCTableView.h"
#include "curl/curl.h"
#include "platform/CCFileUtils.h"
#include "../extensions/GUI/CCEditBox/CCEditBox.h"
#include "SimpleAudioEngine.h"
#include "pthread.h"
#include <thread>
#include <chrono>

using namespace std;
using namespace cocos2d;
using namespace CocosDenshion;
using namespace cocos2d::extension;

#define NT_SLEEP(_TIME_)	std::this_thread::sleep_for(std::chrono::milliseconds(_TIME_));
#define NT_SLEEP_100		NT_SLEEP(rand() % 100);

class NTThread;
class NTMutex
{
	friend NTThread;
public:
	NTMutex()
	{
		isLock = false;
		isInit = false;
	}
private:
	bool isLock;
	bool isInit;
};

class NTThread
{
public:
	static void run(void (*p)())
	{
		NTThread::p= p;

		pthread_t s_loadDataThread;
		pthread_create(&s_loadDataThread, NULL, subThread, NULL);
		pthread_detach(s_loadDataThread);
	}
	static void initMutex(NTMutex *mutex)
	{
		mutex->isInit = true;
	}
	static void lock(NTMutex *mutex)
	{
		CCAssert(mutex->isInit, "Must init mutex var befor lock");
		while (mutex->isLock)
		{
			NT_SLEEP_100;
		}
		mutex->isLock = true;
	}
	static void unlock(NTMutex *mutex)
	{
		CCAssert(mutex->isInit, "Must init mutex var befor unlock");
		mutex->isLock = false;
	}	
private:
	static void* subThread(void *data)
	{
		p();
		return NULL;
	}
protected:
	static void (*p)();
};

#include "NTDefine.h"
#include "Boundary.h"

enum NTGamePlayType
{
	DefaultGamePlay = 0,
	PlayType_Timer,
	PlayType_Heart
};

#include "GameDefine.h"

#define NT_FPS_DEFAULT		30	// save battery
#define FRAME_RATE			(1.0f/30)

#define PI 3.14159265358979f
#define SET_MAX(_X_, _MAX_)	if (_X_ > _MAX_) _X_ = _MAX_;
#define SET_MIN(_X_, _MIN_)	if (_X_ < _MIN_) _X_ = _MIN_;
#define SET_MIN_MAX(_MIN_, _X_, _MAX_) if (_X_ > _MAX_) _X_ = _MAX_; else if (_X_ < _MIN_) _X_ = _MIN_;


#define STEP_MAP_HEIGHT					960

CCLabelTTF* getLabelTTF(string text, int maxFontSize, const CCSize& dimensions, const CCPoint& position=CCPoint(0,0), CCTextAlignment alignment= kCCTextAlignmentCenter, bool fast = false);


struct NTCheat
{
	static bool getCheat(long code);
};

#define NTUserDefault	CCUserDefault
#define KEY_SAVE_TEMPSCORE    "temp_score"


class NTLayer : public CCLayer
{
public: 
	static NTGamePlayType GamePlayType;
};

class IngameLayer : public CCLayer
{
public:
virtual void setPause()=0;
	virtual void setResume()=0;
	virtual bool getRunning()=0;
};

#define STEP_MAP_HEIGHT					960
enum MapTypeStep
{
	MapTypeStepSoid = 1,
	MapTypeStepBridge,
};

enum MapType
{
	MTS = STEP_MAP_HEIGHT * MapTypeStepSoid,	// MapTypeSoid
	MTB = STEP_MAP_HEIGHT * MapTypeStepBridge,	// MapTypeBridge
};


enum NTShapeType
{
	NTShapeTypeBox = 1,
	NTShapeTypeCircle,
};

typedef struct NTShapeData
{
	NTShapeData()
	{};

	NTShapeData(int _shapeType, float _fWidth, float _fHeight, float _fDensityScale, float _fFrictionScale, float _fRestitutionScale) : 
		shapeType(_shapeType), fWidth(_fWidth), fHeight(_fHeight), fDensityScale(_fDensityScale), fFrictionScale(_fFrictionScale), fRestitutionScale(_fRestitutionScale)
	{};

	int shapeType;
	float fWidth;
	float fHeight;

	float fDensityScale;
	float fFrictionScale;
	float fRestitutionScale;
} NTShapeData;

typedef struct ObjBoundaryWheel
{
	CC_SYNTHESIZE(float,			m_fRadius,				Radius);
	CC_SYNTHESIZE(CCPoint,			m_ccpPosition,			Position);
}  ObjBoundaryWheel;

typedef struct ObjBoundaryContact
{
	CC_SYNTHESIZE(bool,				m_bVisible,				Visible);
	CC_SYNTHESIZE(CCPoint,			m_ccpAnchorBodyA,		AnchorBodyA);
	CC_SYNTHESIZE(CCPoint,			m_ccpAnchorBodyB,		AnchorBodyB);
}  ObjBoundaryContact;

typedef struct ObjBoundaryItem
{
	CC_SYNTHESIZE(bool,				m_bVisible,				Visible);

	CC_SYNTHESIZE(CCPoint,			m_ccpTopLeft,			TopLeft);
	CC_SYNTHESIZE(CCPoint,			m_ccpTopRight,			TopRight);
	CC_SYNTHESIZE(CCPoint,			m_ccpMidLeft,			MidLeft);
	CC_SYNTHESIZE(CCPoint,			m_ccpMidRight,			MidRight);
	CC_SYNTHESIZE(CCPoint,			m_ccpBotLeft,			BotLeft);
	CC_SYNTHESIZE(CCPoint,			m_ccpBotRight,			BotRight);

	CC_SYNTHESIZE(CCPoint,			m_ccpCenter,			Center);
	CC_SYNTHESIZE(CCPoint,			m_ccpAnchor,			Anchor);
	CC_SYNTHESIZE(CCPoint,			m_ccpPosition,			Position);

	CC_SYNTHESIZE(ObjBoundaryContact, m_objContact,			Contact);

}  ObjBoundaryItem;

typedef struct ObjBoundaryComponent
{
	CC_SYNTHESIZE(ObjBoundaryWheel, m_objFrontWheel,		FrontWheel);
	CC_SYNTHESIZE(ObjBoundaryWheel, m_objRearWheel,			RearWheel);

	CC_SYNTHESIZE(ObjBoundaryItem, m_objVehicleBody,		VehicleBody);
	CC_SYNTHESIZE(ObjBoundaryItem, m_objPlayerHead,			PlayerHead);
	CC_SYNTHESIZE(ObjBoundaryItem, m_objPlayerBody,			PlayerBody);

	CC_SYNTHESIZE(ObjBoundaryItem, m_objPlayerFrontArm,		PlayerFrontArm);
	CC_SYNTHESIZE(ObjBoundaryItem, m_objPlayerFrontHand,	PlayerFrontHand);
	CC_SYNTHESIZE(ObjBoundaryItem, m_objPlayerFrontThigh,	PlayerFrontThigh);
	CC_SYNTHESIZE(ObjBoundaryItem, m_objPlayerFrontLeg,		PlayerFrontLeg);

	CC_SYNTHESIZE(ObjBoundaryItem, m_objPlayerBehindArm,	PlayerBehindArm);
	CC_SYNTHESIZE(ObjBoundaryItem, m_objPlayerBehindHand,	PlayerBehindHand);
	CC_SYNTHESIZE(ObjBoundaryItem, m_objPlayerBehindThigh,	PlayerBehindThigh);
	CC_SYNTHESIZE(ObjBoundaryItem, m_objPlayerBehindLeg,	PlayerBehindLeg);
}  ObjBoundaryComponent;

typedef struct ObjBoundary
{
	CC_SYNTHESIZE(CCPoint, m_ccpTopLeft,	TopLeft);
	CC_SYNTHESIZE(CCPoint, m_ccpTopRight,	TopRight);
	CC_SYNTHESIZE(CCPoint, m_ccpMidLeft,	MidLeft);
	CC_SYNTHESIZE(CCPoint, m_ccpMidRight,	MidRight);
	CC_SYNTHESIZE(CCPoint, m_ccpBotLeft,	BotLeft);
	CC_SYNTHESIZE(CCPoint, m_ccpBotRight,	BotRight);
	
	CC_SYNTHESIZE(ObjBoundaryComponent*, m_pObjComponent, Component);

	void deleteData()
	{
		if(m_pObjComponent != NULL)
		{
			delete m_pObjComponent;
		}
	};

} ObjBoundary;

class ResourceManager
{
public:
	//void readObjBoundaryFile();
	static ResourceManager* instance;
	static ResourceManager* getInstance();
	CCSprite* createWithSpriteFrameName(string name) {return CCSprite::create(("images/"+name).c_str());}
	CCSprite* createWithSpriteFrameNameWithoutScale(string frameName) {return createWithSpriteFrameName(frameName);};
	CCSpriteFrame* getSpriteFrameByName(string frameName) 
	{
		CCSprite* tmp = createWithSpriteFrameName(frameName); 
		return tmp==NULL? NULL: CCSpriteFrame::create(("images/"+frameName).c_str(), CCRect(0,0,tmp->getContentSize().width,tmp->getContentSize().height));
	}
	CCTexture2D* getTexture(string str, bool mustUse)
	{
		str = "images/" + str;
		CCTexture2D *tex= CCTextureCache::sharedTextureCache()->addImage(str.c_str());
		return CCTextureCache::sharedTextureCache()->textureForKey(str.c_str());
	}

		bool			loadPlistInfo(string fileName);
	// Root name is a tyle (kind) of name EX: "car" mean you want to get a list of "car01", "car02", "car03", "car04" ..
	//CCArray*		getArrayFrameFromRootFileName(string root, int startNum = -1, int endNum = -1, int arrExcept[] = ResourceManager::getInstance()->defaultArray);
	CCAnimation*	getAnimation(CCArray* arrFrames);
	CCMenuItemImage* createMenuItemImageWithFrameName(const char *normalImage, const char *selectedImage, CCObject* target, SEL_MenuHandler selector, bool scale=true, bool onlyCCMenuItemImage=false);
	// this function create for when touch it -> it will become in pices or the action of select image is moving
	CCMenuItemImage* createNTMenuItemImageWithFrameName(const char *normalImage, const char *selectedImage, CCObject* target, SEL_MenuHandler selector, string strHalfLeftImage = "", string strHalfRightImage = "", bool scale = true);
	const ObjBoundary*	getObjBoundaryByImageName(string strName);
	bool haveSpriteFrame(string fileName)
	{
		return createWithSpriteFrameName(fileName)? true: false;
	}

	map<int, CCPoint> ArrMap;
	map<int, int> ArrCreateMetro;
	map<int, int> ArrCreateCoin;
	map<int, int> ArrCreateShape;
	map<int, int> ArrCoinValue;
	map<int, NTShapeData> ArrShapeData;

	map<string, int>			m_fontSize;
	map<string, ObjBoundary>	m_mapObjBoundary;
	CCNode* creatLabelNodeXXX(string text, string font);
	void readObjBoundaryFile();
	ObjBoundaryItem getBoundaryItem(string strName, tinyxml2::XMLElement* pElement);
};

class SoundManager
{
public:
	static SoundManager* instance;
	static SoundManager* getInstance();
	unsigned int playEffect(const char* fileName, bool bLoop = false) {return SimpleAudioEngine::sharedEngine()->playEffect((string("sounds/")+fileName+".wav").c_str(), bLoop);};
	void playBackgroundMusic(string backgroundName) {SimpleAudioEngine::sharedEngine()->playBackgroundMusic((string("sounds/")+backgroundName+".wav").c_str(), true);};
};

class StringManager
{
public:
	static StringManager* instance;
	static StringManager* GetInstance();
	string GetString(string strId) {return strId;};
};
#define GetLocalizedString(stringId) StringManager::GetInstance()->GetString(stringId)

class NetworkManager : public CCObject
{
public:		
	static NetworkManager* instance;
	static NetworkManager* getInstance();
	void sendScoreToServer(int totalscore, int totalstar, int level, string strModeName = "")
	{ CCLOG("NETWORK MANAGER SEND SCORE TO SERVER: score=%d, star=%d, level=%d, mode=%s", totalscore, totalstar, level, strModeName.c_str()); };
};

class Encrypt
{
public:
	static string getFileName(string path) {return path;}
};

string IntToString(int poker);
CCSprite* getBlackBackground(uint8_t alpha);

#define	IMG_BG_INGAME					"bgIngame.png"

#define KEY_SAVE_TEMPSCORE				"temp_score"
#define KEY_SAVE_TEMPSTAR_1				"temp_star1"
#define KEY_SAVE_TEMPSTAR_2				"temp_star2"
#define KEY_SAVE_TEMPSTAR_3				"temp_star3"
#define KEY_SAVE_TEMPLEVEL				"temp_level"
#define KEY_SAVE_USERNAME				"username"

#endif